home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / pop2serv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-06  |  25.1 KB  |  871 lines

  1. /* POP2 Server state machine - see RFC 937
  2.  *
  3.  *  also see other credits in popcli.c
  4.  *  10/89 Mike Stockett wa7dyx
  5.  *  Modified 5/27/90 by Allen Gwinn, N5CKP, for later NOS releases.
  6.  *  Added to NOS by PA0GRI 2/6/90 (and linted into "standard" C)
  7.  *
  8.  *      Aug-Oct 92      Mike Bilow, N1BEE, mikebw@ids.net
  9.  *              Extensive bug fixes, changed uses of Borland stat()
  10.  *              to fsize() in order to fix intermittent crashes
  11.  *
  12.  *    November 93    KO4KS/Brian A. Lantz
  13.  *        Modified close_folder() for TNOS control files
  14.  *
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <fcntl.h>
  19. #include <time.h>
  20. #include <sys/stat.h>
  21. #ifdef UNIX
  22. #include <sys/types.h>
  23. #endif
  24. #if     defined(__STDC__) || defined(__TURBOC__)
  25. #include <stdarg.h>
  26. #endif
  27. #include <ctype.h>
  28. #include <setjmp.h>
  29. #include "global.h"
  30. #include "mbuf.h"
  31. #include "cmdparse.h"
  32. #include "socket.h"
  33. #include "proc.h"
  34. #include "files.h"
  35. #include "smtp.h"
  36. #include "mailbox.h"
  37. #include "bm.h"
  38. #include "mailcli.h"                    /* N1BEE */
  39.  
  40. #undef DEBUG                            /* N1BEE */
  41.  
  42.  
  43. /* ---------------- common server data structures ---------------- */
  44.  
  45. /* POP server control block */
  46.  
  47. struct pop_scb {
  48.         int     socket;         /* socket number for this connection */
  49.         char    state;          /* server state */
  50. #define         LSTN    0
  51. #define         AUTH    1
  52. #define         MBOX    2
  53. #define         ITEM    3
  54. #define         NEXT    4
  55. #define         DONE    5
  56.         char    buf[TLINELEN+1];        /* input line buffer */
  57.         char    count;          /* line buffer length */
  58.         char    username[32];   /* user/folder name */
  59.         FILE    *wf;            /* work folder file pointer */
  60.         int     folder_len;     /* number of msgs in current folder */
  61.         int     msg_num;        /* current msg number */
  62.         long    msg_len;        /* length of current msg */
  63.         int     msg_status_size; /* size of the message status array */
  64.         long    curpos;         /* current msg's position in file */
  65.         long    folder_file_size; /* length of the current folder file, in bytes */
  66.         long    nextpos;        /* next msg's position in file */
  67.         char    folder_modified; /* mail folder contents modified flag */
  68.         int16   *msg_status;    /* message status array pointer */
  69. };
  70.  
  71. #define NULLSCB         (struct pop_scb *)0
  72.  
  73. /* Response messages */
  74.  
  75. static char     count_rsp[]    = "#%d messages in this folder\n",
  76.                 error_rsp[]    = "- ERROR: %s\n",
  77.                 greeting_msg[] = "+ POP2 %s\n",
  78. /*              length_rsp[]   = "=%ld bytes in this message\n", */
  79.                 length_rsp[]   = "=%ld characters in Message #%d\n",
  80.                 msg_line[]     = "%s\n",
  81.                 no_mail_rsp[]  = "+ No mail, sorry\n",
  82.                 no_more_rsp[]  = "=%d No more messages in this folder\n",
  83.                 signoff_msg[]  = "+ Bye, thanks for calling\n";
  84.  
  85. static void rrip __ARGS((char *s));
  86. static struct pop_scb *create_scb __ARGS((void));
  87. static void delete_scb __ARGS((struct pop_scb *scb));
  88. static void popserv __ARGS((int s,void *unused,void *p));
  89. static int poplogin __ARGS((char *pass,char *username));
  90.  
  91. static void pop_sm __ARGS((struct pop_scb *scb));
  92.  
  93. static int Spop = -1; /* prototype socket for service */
  94.  
  95.  
  96. /* Start up POP receiver service */
  97. int
  98. pop2start(argc,argv,p)
  99. int argc;
  100. char *argv[];
  101. void *p;
  102. {
  103.     return (installserver (argc, argv, &Spop, "POP2 listener", IPPORT_POP2,
  104.         "POP2 server", popserv, 4096, NULL));
  105. }
  106.  
  107. /* Shutdown POP2 service (existing connections are allowed to finish) */
  108.  
  109. int
  110. pop2stop(argc,argv,p)
  111. int argc;
  112. char *argv[];
  113. void *p;
  114. {
  115.     return (deleteserver (&Spop));
  116. }
  117.  
  118. static void
  119. popserv(s,unused,p)
  120. int s;
  121. void *unused;
  122. void *p;
  123. {
  124.         struct pop_scb *scb;
  125.  
  126.         sockowner(s,Curproc);           /* We own it now */
  127.         log(s,"open POP2");
  128.  
  129.         if((scb = create_scb()) == NULLSCB) {
  130.                 tprintf(Nospace);
  131.                 log(s,"close POP2 - no space");
  132.                 close_s(s);
  133.                 return;
  134.         }
  135.  
  136.         scb->socket = s;
  137.         scb->state  = AUTH;
  138.  
  139.         (void) usprintf(s,greeting_msg,Hostname);
  140.  
  141. loop:   if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  142.                 /* He closed on us */
  143.  
  144.                 goto quit;
  145.         }
  146.  
  147.         rrip(scb->buf);         /* Was "rip()" not "rrip()" -- N1BEE */
  148.         if (strlen(scb->buf) == 0)      /* Ignore blank cmd lines */
  149.                 goto loop;
  150.  
  151. #ifdef DEBUG
  152.         if(Mailtrace >= 3) {
  153.                 tprintf("POP2SERV(popserv): Processing line <%s>\n",scb->buf);
  154.                 /* getch(); */
  155.         }
  156. #endif /* DEBUG */
  157.  
  158.         pop_sm(scb);
  159.         if (scb->state == DONE)
  160.                 goto quit;
  161.  
  162.         goto loop;
  163.  
  164. quit:
  165.         log(scb->socket,"close POP2");
  166.         close_s(scb->socket);
  167.         delete_scb(scb);
  168. }
  169.  
  170.  
  171. /* Create control block, initialize */
  172.  
  173. static struct
  174. pop_scb *create_scb()
  175. {
  176.         register struct pop_scb *scb;
  177.  
  178.         if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  179.                 return NULLSCB;
  180.  
  181.         scb->username[0] = '\0';
  182.         scb->msg_status = NULL;
  183.         scb->wf = NULL;
  184.  
  185.         scb->count = scb->folder_file_size = scb->msg_num = 0;
  186.  
  187.         scb->folder_modified = FALSE;
  188.         return scb;
  189. }
  190.  
  191.  
  192. /* Free resources, delete control block */
  193.  
  194. static void
  195. delete_scb(scb)
  196. register struct pop_scb *scb;
  197. {
  198.  
  199.         if (scb == NULLSCB)
  200.                 return;
  201.         if (scb->wf != NULL)
  202.                 fclose(scb->wf);
  203.         if (scb->msg_status  != NULL)
  204.                 free((char *)scb->msg_status);
  205.  
  206.         free((char *)scb);
  207. }
  208.  
  209. /* replace terminating end of line marker(s) (\r and \n) with null */
  210. static void
  211. rrip(s)
  212. register char *s;
  213. {
  214.         register char *cp;
  215.  
  216.         if((cp = strchr(s,'\r')) != NULLCHAR)
  217.                 *cp = '\0';
  218. #ifndef TNOS_68K
  219.     if((cp = strchr(s,'\n')) != NULLCHAR)
  220. #else
  221.     if((cp = strchr(s,'\l')) != NULLCHAR)
  222. #endif
  223.                 *cp = '\0';
  224. }
  225.  
  226. /* --------------------- start of POP server code ------------------------ */
  227.  
  228. #define BITS_PER_WORD   16
  229.  
  230. #define isSOM(x)        ((strncmp(x,"From ",5) == 0))   /* Start Of Message */
  231.  
  232. /* Command string specifications */
  233.  
  234. static char     ackd_cmd[] = "ACKD",
  235.                 acks_cmd[] = "ACKS",
  236. #ifdef POP_FOLDERS
  237.                 fold_cmd[] = "FOLD ",
  238. #endif
  239.                 login_cmd[] = "HELO ",
  240.                 nack_cmd[] = "NACK",
  241.                 quit_cmd[] = "QUIT",
  242.                 read_cmd[] = "READ",
  243.                 retr_cmd[] = "RETR";
  244.  
  245. static void
  246. pop_sm(scb)
  247. struct pop_scb *scb;
  248. {
  249.         char password[30];
  250.         void state_error __ARGS((struct pop_scb *,char *));
  251.         void open_folder __ARGS((struct pop_scb *));
  252.         void do_cleanup __ARGS((struct pop_scb *));
  253.         void read_message __ARGS((struct pop_scb *));
  254.         void retrieve_message __ARGS((struct pop_scb *));
  255.         void deletemsg __ARGS((struct pop_scb *,int));
  256.         void get_message __ARGS((struct pop_scb *,int));
  257.         void print_message_length __ARGS((struct pop_scb *));
  258.         void close_folder __ARGS((struct pop_scb *));
  259. #ifdef POP_FOLDERS
  260.         void select_folder __ARGS((struct pop_scb *));
  261. #endif
  262.  
  263.         if (scb == NULLSCB)     /* be certain it is good -- wa6smn */
  264.                 return;
  265.  
  266.         switch(scb->state) {
  267.         case AUTH:
  268. #ifdef DEBUG
  269.                 if(Mailtrace >= 3)
  270.                         tprintf("POP2SERV(pop_sm): Entering case AUTH\n");
  271. #endif /* DEBUG */
  272.                 if (strncmp(scb->buf,login_cmd,strlen(login_cmd)) == 0){
  273.                         sscanf(scb->buf,"HELO %31s %29s",scb->username,password);
  274. #ifdef DEBUG
  275.                         if(Mailtrace >= 3) {
  276.                                 tprintf("POP2SERV(pop_sm): Processing USER %s PASS %s\n",scb->username,password);
  277.                                 tprintf("POP2SERV(pop_sm): Calling poplogin() for %s:%s:\n",scb->username,password);
  278.                         }
  279. #endif /* DEBUG */
  280.  
  281.                         if (!poplogin(scb->username,password)) {
  282.                                 log(scb->socket,"POP2 access DENIED to %s",
  283.                                             scb->username);
  284.                                 state_error(scb,"Access DENIED!!");
  285.                                 return;
  286.                         }
  287.  
  288.                         log(scb->socket,"POP2 access granted to %s",
  289.                                     scb->username);
  290.                         open_folder(scb);
  291.                 } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  292.                         do_cleanup(scb);
  293.                 } else
  294.                         state_error(scb,"(AUTH) Expected HELO or QUIT command");
  295. #ifdef DEBUG
  296.                 if(Mailtrace >= 3)
  297.                         tprintf("POP2SERV(pop_sm): Leaving case AUTH\n");
  298. #endif /* DEBUG */
  299.                 break;
  300.  
  301.         case MBOX:
  302.                 if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  303.                         read_message(scb);
  304.  
  305. #ifdef POP_FOLDERS
  306.                 else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  307.                         select_folder(scb);
  308.  
  309. #endif
  310.  
  311.                 else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0) {
  312.                         do_cleanup(scb);
  313.                 } else
  314.                         state_error(scb,
  315. #ifdef POP_FOLDERS
  316.                                     "(MBOX) Expected FOLD, READ, or QUIT command");
  317. #else
  318.                                     "(MBOX) Expected READ or QUIT command");
  319. #endif
  320.                 break;
  321.  
  322.         case ITEM:
  323.                 if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  324.                         read_message(scb);
  325.  
  326. #ifdef POP_FOLDERS
  327.  
  328.                 else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  329.                         select_folder(scb);
  330. #endif
  331.  
  332.                 else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  333.                         retrieve_message(scb);
  334.                 else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  335.                         do_cleanup(scb);
  336.                 else
  337.                         state_error(scb,
  338. #ifdef POP_FOLDERS
  339.                            "(ITEM) Expected FOLD, READ, RETR, or QUIT command");
  340. #else
  341.                            "(ITEM) Expected READ, RETR, or QUIT command");
  342. #endif
  343.                 break;
  344.  
  345.         case NEXT:
  346.                 if (strncmp(scb->buf,ackd_cmd,strlen(ackd_cmd)) == 0){
  347.                                 /* ACKD processing */
  348.                         deletemsg(scb,scb->msg_num);
  349.                         scb->msg_num++;
  350.                         get_message(scb,scb->msg_num);
  351.                 } else if (strncmp(scb->buf,acks_cmd,strlen(acks_cmd)) == 0){
  352.                                 /* ACKS processing */
  353.                         scb->msg_num++;
  354.                         get_message(scb,scb->msg_num);
  355.                 } else if (strncmp(scb->buf,nack_cmd,strlen(nack_cmd)) == 0){
  356.                                 /* NACK processing */
  357.                         fseek(scb->wf,scb->curpos,SEEK_SET);
  358.                 } else {
  359.                         state_error(scb,"(NEXT) Expected ACKD, ACKS, or NACK command");
  360.                         return;
  361.                 }
  362.  
  363.                 print_message_length(scb);
  364.                 scb->state  = ITEM;
  365.                 break;
  366.  
  367.         case DONE:
  368.                 do_cleanup(scb);
  369.                 break;
  370.  
  371.         default:
  372.                 state_error(scb,"(TOP) State Error!!");
  373.                 break;
  374.         }
  375.  
  376. #ifdef DEBUG
  377.         if(Mailtrace >= 3)
  378.                 tprintf("POP2SERV(pop_sm): Leaving state machine; state %u\n",scb->state);
  379. #endif /* DEBUG */
  380. }
  381.  
  382. static void
  383. do_cleanup(scb)
  384. struct pop_scb *scb;
  385. {
  386.         void close_folder __ARGS((struct pop_scb *));
  387.  
  388.         close_folder(scb);
  389.         (void) usprintf(scb->socket,signoff_msg);
  390.         scb->state = DONE;
  391. }
  392.  
  393. static void
  394. state_error(scb,msg)
  395. struct pop_scb *scb;
  396. char *msg;
  397. {
  398.         if(Mailtrace >= 2)
  399.                 tprintf(error_rsp,msg);
  400.         (void) usprintf(scb->socket,error_rsp,msg);
  401.         scb->state = DONE;
  402. }
  403.  
  404. #ifdef POP_FOLDERS
  405.  
  406. static void
  407. select_folder(scb)
  408. struct pop_scb  *scb;
  409. {
  410.         sscanf(scb->buf,"FOLD %s",scb->username);
  411.  
  412.         if (scb->wf != NULL)
  413.                 close_folder(scb);
  414.  
  415.         open_folder(scb);
  416. }
  417.  
  418. #endif
  419.  
  420.  
  421. static void
  422. close_folder(scb)
  423. struct pop_scb *scb;
  424. {
  425.         char folder_pathname[64];
  426.         char line[TLINELEN+1];
  427.         FILE *fd;
  428.         int deleted = FALSE;
  429.         int msg_no = 0;
  430.         struct stat folder_stat;
  431.         int newmail __ARGS((struct pop_scb *));
  432.         int isdeleted __ARGS((struct pop_scb *,int));
  433.     char *cp;
  434.     int firstIDline = 0, nextisBID = 0, k;
  435.     int public, lines = 0;
  436.     long last;
  437.     struct let lt;
  438.  
  439.         if (scb->wf == NULL)
  440.                 return;
  441.  
  442.         if (!scb->folder_modified) {
  443.                 /* no need to re-write the folder if we have not modified it */
  444.  
  445.                 fclose(scb->wf);
  446.                 scb->wf = NULL;
  447.  
  448.                 free((char *)scb->msg_status);
  449.                 scb->msg_status = NULL;
  450.                 return;
  451.         }
  452.  
  453.  
  454.         sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  455.  
  456.         if (newmail(scb)) {
  457.                 /* copy new mail into the work file and save the
  458.                    message count for later */
  459.  
  460.                 if ((fd = fopen(folder_pathname,"r")) == NULL) {
  461.                         state_error(scb,"Unable to add new mail to folder");
  462.                         return;
  463.                 }
  464.  
  465.                 fseek(scb->wf,0,SEEK_END);
  466.                 fseek(fd,scb->folder_file_size,SEEK_SET);
  467.                 while (!feof(fd)) {
  468.                         fgets(line,TLINELEN,fd);
  469.                         fputs(line,scb->wf);
  470.                 }
  471.  
  472.                 fclose(fd);
  473.         }
  474.  
  475.         /* now create the updated mail folder */
  476.  
  477.         if ((fd = fopen(folder_pathname,"w")) == NULL){
  478.                 state_error(scb,"Unable to update mail folder");
  479.                 return;
  480.         }
  481.  
  482.         rewind(scb->wf);
  483.  
  484.     sprintf(line,"%s/CONTROL/%s.ctl",Mailspool,scb->username);
  485.     remove (line);
  486.     lt.start = last = 0;
  487.  
  488.         while (!feof(scb->wf)){
  489.                 fgets(line,TLINELEN,scb->wf);
  490.                 if (feof(scb->wf))
  491.                     continue;
  492.         pwait(NULL);    /* give other processes time in long copy */
  493.  
  494.                 if (isSOM(line)){
  495.             lt.size = last - lt.start - lines; 
  496.             if (lt.size && (deleted == FALSE))
  497.                 updateCtl (scb->username, <);
  498.             lines = lt.status = 0;
  499.             lt.start = last;
  500.             firstIDline = 0;
  501.  
  502.                         msg_no++;
  503.                         if (msg_no <= scb->folder_len)
  504.                                 deleted = isdeleted(scb,msg_no);
  505.                         else
  506.                                 deleted = FALSE;
  507.                 }
  508.  
  509.  
  510.         lines++;
  511.         if (!firstIDline && nextisBID && (cp=strstr(line,"AA")) != NULLCHAR) {
  512.             /*what follows is the message-number*/
  513.             lt.bid = atol(cp+2);
  514.             nextisBID = 0;
  515.             firstIDline = 1;
  516.             }
  517.  
  518.         if (!strncmp ("Received: ", line, 10))
  519.             nextisBID = 1;
  520.         if (!strncmp ("Status: R", line, 9))
  521.             lt.status = BM_READ;
  522.  
  523.                 if (deleted)
  524.                         continue;
  525.  
  526.                 fputs(line,fd);
  527.         last = ftell (fd);
  528.         }
  529.  
  530.     lt.size = last - lt.start - lines; 
  531.     if (deleted == FALSE)
  532.         updateCtl (scb->username, <);
  533.  
  534.         fclose(fd);
  535.  
  536.         /* trash the updated mail folder if it is empty */
  537.  
  538. /*      if ((stat(folder_pathname,&folder_stat) == 0) && (folder_stat.st_size == 0)) */
  539.         if(fsize(folder_pathname) == 0L)                /* N1BEE */
  540.                 unlink(folder_pathname);
  541.  
  542.         fclose(scb->wf);
  543.         scb->wf = NULL;
  544.  
  545.         free((char *)scb->msg_status);
  546.         scb->msg_status = NULL;
  547. }
  548.  
  549. static void
  550. open_folder(scb)
  551. struct pop_scb  *scb;
  552. {
  553.         char folder_pathname[64];
  554.         char line[TLINELEN+1];
  555.         FILE *fd;
  556. /*      FILE *tmpfile();                should not declare here -- N1BEE */
  557.         struct stat folder_stat;
  558.  
  559.  
  560.         sprintf(folder_pathname,"%.45s/%.8s.txt",Mailspool,scb->username);
  561. #ifdef DEBUG
  562.         if(Mailtrace >= 3) {
  563.                 tprintf("POP2SERV(open_folder): will open %s\n",folder_pathname);
  564.         }
  565. #endif /* DEBUG */
  566.         scb->folder_len       = 0;
  567.         scb->folder_file_size = 0;
  568.  
  569.         /* Ordinarily, we would call stat() to find out if the file exists
  570.            and get its size at the same time.  However, there is a bug in
  571.            Borland's stat() code which crashes DesqView and OS/2 (!) if
  572.            stat() is called on a file which does not exist.  -- N1BEE
  573.         */
  574.  
  575.         /* if (stat(folder_pathname,&folder_stat)){ */
  576.         if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  577. #ifdef DEBUG
  578.                 if(Mailtrace >= 3) {
  579.                         tprintf("POP2SERV(open_folder): folder not found (empty)\n");
  580.                 }
  581. #endif /* DEBUG */
  582.                 (void) usprintf(scb->socket,no_mail_rsp);
  583.  
  584.                 /* state remains AUTH, expecting HELO or QUIT */
  585.                 return;
  586.         }
  587.  
  588.         scb->folder_file_size = folder_stat.st_size;
  589.         if ((fd = fopen(folder_pathname,"r")) == NULL){
  590.                 state_error(scb,"POP2SERV(open_folder): Unable to open mail folder");
  591.                 return;
  592.         }
  593.  
  594.         if ((scb->wf = tmpfile()) == NULL) {
  595.                 state_error(scb,"POP2SERV(open_folder): Unable to create work folder");
  596.                 return;
  597.         }
  598.  
  599.         while(!feof(fd)) {
  600.                 fgets(line,TLINELEN,fd);
  601.  
  602.                 /* scan for begining of a message */
  603.  
  604.                 if (isSOM(line))
  605.                         scb->folder_len++;
  606.  
  607.                 /* now put  the line in the work file */
  608.  
  609.                 fputs(line,scb->wf);
  610.         }
  611.  
  612.         fclose(fd);
  613.  
  614.         scb->msg_status_size = (scb->folder_len) / BITS_PER_WORD;
  615.  
  616.         if ((((scb->folder_len) % BITS_PER_WORD) != 0) ||
  617.             (scb->msg_status_size == 0))
  618.                 scb->msg_status_size++;
  619.  
  620.         if ((scb->msg_status = (int16 *) callocw(scb->msg_status_size,
  621.                                 sizeof(int16))) == NULL) {
  622.                 state_error(scb,"Unable to create message status array");
  623.                 return;
  624.         }
  625.  
  626.         (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  627.  
  628.         scb->state  = MBOX;
  629.  
  630. #ifdef DEBUG
  631.         if(Mailtrace >= 3)
  632.                 tprintf("POP2SERV: open_folder() completed successfully.\n");
  633. #endif /* DEBUG */
  634. }
  635.  
  636. static void
  637. read_message(scb)
  638. struct pop_scb  *scb;
  639. {
  640.         void get_message __ARGS((struct pop_scb *,int));
  641.         void print_message_length __ARGS((struct pop_scb *));
  642.  
  643.         if (scb == NULLSCB)     /* check for null -- wa6smn */
  644.                 return;
  645.         if (scb->buf[sizeof(read_cmd) - 1] == ' ')
  646.                 scb->msg_num = atoi(&(scb->buf[sizeof(read_cmd) - 1]));
  647.         else
  648.                 scb->msg_num++;
  649.  
  650.         get_message(scb,scb->msg_num);
  651.         print_message_length(scb);
  652.         scb->state  = ITEM;
  653. }
  654.  
  655. static void
  656. retrieve_message(scb)
  657. struct pop_scb  *scb;
  658. {
  659.         char line[TLINELEN+1];
  660.         long cnt;
  661.  
  662.         if (scb == NULLSCB)     /* check for null -- wa6smn */
  663.                 return;
  664.         if (scb->msg_len == 0) {
  665.                 state_error(scb,"Attempt to access a DELETED message!");
  666.                 return;
  667.         }
  668.  
  669.         cnt  = scb->msg_len;
  670.         while(!feof(scb->wf) && (cnt > 0)) {
  671.                 fgets(line,TLINELEN,scb->wf);
  672.                 rrip(line);
  673.  
  674.                 (void) usprintf(scb->socket,msg_line,line);
  675.                 cnt -= (strlen(line)+2);        /* Compensate for CRLF */
  676.         }
  677.  
  678.         scb->state = NEXT;
  679. }
  680.  
  681. static void
  682. get_message(scb,msg_no)
  683. struct pop_scb  *scb;
  684. int msg_no;
  685. {
  686.         char line[TLINELEN+1];
  687.         long ftell();
  688.  
  689.         if (scb == NULLSCB)     /* check for null -- wa6smn */
  690.                 return;
  691.         scb->msg_len = 0;
  692.         if (msg_no > scb->folder_len) {
  693.                 scb->curpos  = 0;
  694.                 scb->nextpos = 0;
  695.                 return;
  696.         } else {
  697.                 /* find the message and its length */
  698.  
  699.                 rewind(scb->wf);
  700.                 while (!feof(scb->wf) && (msg_no > -1)) {
  701.                         if (msg_no > 0)
  702.                                 scb->curpos = ftell(scb->wf);
  703.                         
  704.                         fgets(line,TLINELEN,scb->wf);
  705.                         rrip(line);
  706.  
  707.                         if (isSOM(line))
  708.                                 msg_no--;
  709.  
  710.                         if (msg_no != 0)
  711.                                 continue;
  712.  
  713.                         scb->nextpos  = ftell(scb->wf);
  714.                         scb->msg_len += (strlen(line)+2);       /* Add CRLF */
  715.                 }
  716.         }
  717.  
  718.         if (scb->msg_len > 0)
  719.                 fseek(scb->wf,scb->curpos,SEEK_SET);
  720.  
  721.         /* we need the pointers even if the message was deleted */
  722.  
  723.         if  (isdeleted(scb,scb->msg_num))
  724.                 scb->msg_len = 0;
  725. }
  726.  
  727. static int
  728. poplogin(username,pass)
  729. char *pass;
  730. char *username;
  731. {
  732.         char buf[80];
  733.         char *cp;
  734.         char *cp1;
  735.         FILE *fp;
  736.  
  737. #ifdef DEBUG
  738.         if(Mailtrace >= 3)
  739.                 tprintf("POP2SERV(poplogin): Opening POP users file %s\n",Popusers);
  740. #endif /* DEBUG */
  741.  
  742.         if((fp = fopen(Popusers,"r")) == NULLFILE) {
  743.                 /* User file doesn't exist */
  744.                 tprintf("POP2 users file %s not found\n",Popusers);
  745.                 return(FALSE);
  746.         }
  747.  
  748. #ifdef DEBUG
  749.         if(Mailtrace >= 3)
  750.                 tprintf("POP2SERV(poplogin): Login request from %s:%s:\n",username,pass);
  751. #endif /* DEBUG */
  752.  
  753.         while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  754.                 if(buf[0] == '#')
  755.                         continue;       /* Comment */
  756.  
  757.                 if((cp = strchr(buf,':')) == NULLCHAR)
  758.                         /* Bogus entry */
  759.                         continue;
  760.  
  761.                 *cp++ = '\0';           /* Now points to password */
  762.                 if(strcmp(username,buf) == 0)
  763.                         break;          /* Found user name */
  764.         }
  765.  
  766.         if(feof(fp)) {
  767. #ifdef DEBUG
  768.                 if(Mailtrace >= 3)
  769.                         tprintf("POP2SERV(poplogin): username not found in POPUSERS\n");
  770. #endif /* DEBUG */
  771.                 /* User name not found in file */
  772.  
  773.                 fclose(fp);
  774.                 return(FALSE);
  775.         }
  776.         fclose(fp);
  777.  
  778.         if ((cp1 = strchr(cp,':')) == NULLCHAR) {
  779. #ifdef DEBUG
  780.                 if(Mailtrace >= 3)
  781.                         tprintf("POP2SERV(poplogin): No second ':' in POPUSERS entry\n");
  782. #endif /* DEBUG */
  783.                 return(FALSE);
  784.         }
  785.  
  786.         *cp1 = '\0';
  787.         if(strcmp(cp,pass) != 0) {
  788. #ifdef DEBUG
  789.                 if(Mailtrace >= 3)
  790.                         tprintf("POP2SERV(poplogin): Wrong password (%s) from user %s, expecting %s\n",pass,username,cp);
  791. #endif /* DEBUG */
  792.                 /* Password required, but wrong one given */
  793.                 return(FALSE);
  794.         }
  795.  
  796.         /* whew! finally made it!! */
  797. #ifdef DEBUG
  798.         if(Mailtrace >= 3)
  799.                 tprintf("POP2SERV(poplogin): %s authenticated\n",username);
  800. #endif /* DEBUG */
  801.  
  802.         return(TRUE);
  803. }
  804.  
  805. static int
  806. isdeleted(scb,msg_no)
  807. struct pop_scb *scb;
  808. int msg_no;
  809. {
  810.         int16 mask = 1,offset;
  811.  
  812.         msg_no--;
  813.         offset = msg_no / BITS_PER_WORD;
  814.         mask <<= msg_no % BITS_PER_WORD;
  815.         return (((scb->msg_status[offset]) & mask)? TRUE:FALSE);
  816. }
  817.  
  818. static void
  819. deletemsg(scb,msg_no)
  820. struct pop_scb *scb;
  821. int msg_no;
  822. {
  823.         int16 mask = 1,offset;
  824.  
  825.         if (scb == NULLSCB)     /* check for null -- wa6smn */
  826.                 return;
  827.         msg_no--;
  828.         offset = msg_no / BITS_PER_WORD;
  829.         mask <<= msg_no % BITS_PER_WORD;
  830.         scb->msg_status[offset] |= mask;
  831.         scb->folder_modified = TRUE;
  832. }
  833.  
  834. static int
  835. newmail(scb)
  836. struct pop_scb *scb;
  837. {
  838.         char folder_pathname[64];
  839.         struct stat folder_stat;
  840.  
  841.         sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  842.  
  843.         /* if (stat(folder_pathname,&folder_stat)) { */
  844.         if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  845.                 state_error(scb,"Unable to get old mail folder's status");
  846.                 return(FALSE);
  847.         } else
  848.                 return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  849. }
  850.  
  851. static void
  852. print_message_length(scb)
  853. struct pop_scb *scb;
  854. {
  855.         char *print_control_string;
  856.  
  857.         if (scb == NULLSCB)     /* check for null -- wa6smn */
  858.                 return;
  859.         if (scb->msg_len > 0)
  860.                 print_control_string = length_rsp;
  861.         else if (scb->msg_num <= scb->folder_len)
  862.                 print_control_string = length_rsp;
  863.         else
  864.                 print_control_string = no_more_rsp;
  865.  
  866.         (void)usprintf(scb->socket,print_control_string,scb->msg_len,scb->msg_num);
  867. }
  868.  
  869.  
  870.  
  871.